/*
 * Lenovo Group
 * Copyright (c) 2015-2016 All Rights Reserved.
 * Project Name: lmrp-android framework
 * Create Time: 16-2-16 下午6:49
 */

package com.lenovo.framework.base;

import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.LinearInterpolator;
import android.view.inputmethod.InputMethodManager;
import android.widget.ImageView;
import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.lenovo.framework.FApplication;
import com.lenovo.framework.R;
import com.lenovo.framework.biz.ContextManager;
import com.lenovo.framework.conf.FConstants;
import com.lenovo.framework.conf.Theme;
import com.lenovo.framework.util.BugFix;
import com.lenovo.framework.util.DLog;
import com.lenovo.framework.util.FPreferenceManager;
import com.lenovo.framework.view.DialogLoadingFragment;
import com.squareup.leakcanary.RefWatcher;
import com.trello.rxlifecycle.components.support.RxAppCompatActivity;
import com.umeng.analytics.MobclickAgent;

import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * Since RxJava is on top of all async processing in activity lifecycle,
 * FBaseActivity is considered to be an instance of RxAppCompatActivity, <b>
 * then observable could use compose to binding activity lifecycle to itself.
 * framework </b>base activity with activity lifecycle debug mode called in debug
 * build; common function like <i>hidekeyboard</i>,  <i>showShortToast</i>,
 * <i>openActivity </i> activity theme, <b>permission request functionality</b>
 * needed in (android6.0) are also customized
 * @author JeffreyHe
 * @version 1.0
 * @updated 16-2月-2016 17:50:42
 */
public abstract class FBaseActivity extends RxAppCompatActivity{

	/**
	 * permisson request code used after android6.0 in activity
	 */
    public static final int REQUEST_PERMISSION = 0x3e;
    public static final String PRE_RESULT = "pre_activity_result";
    protected static String TAG = "BaseActivity";
    private HashMap<String, Runnable> permissionCallbacks = new HashMap<>();

	/**
	 * processbar used for display loading screen with alpa dim on top of activity screen
	 */
    protected DialogLoadingFragment processBar;
	/**
	 * this array list is used for for retrieve data from parent activity, or finish
	 * activities in line
	 */
    protected static final List<Activity> activities = new CopyOnWriteArrayList<Activity>();

	/**
	 * on precreate is used for theme setting to styling activities
	 */
    protected void onPreCreate() {
        final Theme currentTheme = FPreferenceManager.getCurrentTheme();
        switch (currentTheme) {
            case Blue:
                this.setTheme(R.style.BlueTheme);
                break;
            case Green:
                this.setTheme(R.style.GreenTheme);
                break;
            case Red:
                this.setTheme(R.style.RedTheme);
                break;
            case Indigo:
                this.setTheme(R.style.IndigoTheme);
                break;
            case BlueGrey:
                this.setTheme(R.style.BlueGreyTheme);
                break;
            case Black:
                this.setTheme(R.style.BlackTheme);
                break;
            case Orange:
                this.setTheme(R.style.OrangeTheme);
                break;
            case Purple:
                this.setTheme(R.style.PurpleTheme);
                break;
            case Pink:
                this.setTheme(R.style.PinkTheme);
                break;
            default:
                this.setTheme(R.style.BlackTheme);
                break;
        }
    }
    /**
	 * ***********************【Activity LifeCycle For Debug】
	 * **************************
	 *
	 * @param savedInstanceState
	 */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        //keep activity stack trace for later use
        if(!activities.contains(this)) {
            activities.add(this);
        }else{
            activities.remove(this);
            activities.add(this);
        }
        onPreCreate();

        super.onCreate(savedInstanceState);

        for(Activity a : activities) {
            DLog.i("activities", a.getClass().getName());
        }

        TAG = this.getClass().getName();
        DLog.d(TAG, this.getClass().getSimpleName()
                + " onCreate() invoked!!");
        overridePendingTransition(R.anim.activity_open_translate, R.anim.activity_close_scale);
    }

	/**
	 * hide keyboard whenever needed
	 *
	 * @param event
	 */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            if (getCurrentFocus() != null
                    && getCurrentFocus().getWindowToken() != null) {
                hideKeyboard(this.getWindow().getDecorView().findViewById(android.R.id.content));
            }
        }
        return super.onTouchEvent(event);
    }

	/**
	 * show shorttoast is a ease use of Toast.makeText(..,..,..).show();
	 *
	 * @param pResId
	 */
    public void showShortToast(int pResId) {
        showShortToast(getString(pResId));
    }

	/**
	 * show longtoast is a ease use of Toast.makeText(..,..,..).show();
	 *
	 * @param pMsg
	 */
    protected void showLongToast(String pMsg) {
        Toast.makeText(this, pMsg, Toast.LENGTH_LONG).show();
    }

    public void showShortToast(String pMsg) {
        Toast.makeText(this, pMsg, Toast.LENGTH_SHORT).show();
    }

	/**
	 * open activity with constructed intent
	 *
	 * @param pClass
	 */
    protected void openActivity(Class<?> pClass) {
        openActivity(pClass, null);
    }

	/**
	 * open activity with bundle arguments
	 *
	 * @param pClass
	 * @param pBundle
	 */
    public void openActivity(Class<?> pClass, Bundle pBundle) {
        Intent intent = new Intent(this, pClass);
        if (pBundle != null) {
            intent.putExtras(pBundle);
        }
        startActivity(intent);
    }

	/**
	 * open activity with action filter
	 *
	 * @param pAction
	 */
    protected void openActivity(String pAction) {
        openActivity(pAction, null);
    }

	/**
	 * open activity with action filter and bundle arguments
	 *
	 * @param pAction
	 * @param pBundle
	 */
    protected void openActivity(String pAction, Bundle pBundle) {
        Intent intent = new Intent(pAction);
        if (pBundle != null) {
            intent.putExtras(pBundle);
        }
        startActivity(intent);
    }

	/**
	 * common method to hide keyboard
	 *
	 * @param view
	 */
    protected void hideKeyboard(View view) {
        InputMethodManager imm = (InputMethodManager) this
                .getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(view.getWindowToken(),
                InputMethodManager.HIDE_NOT_ALWAYS);
    }

    /**
     * common method to hide keyboard
     *
     * @param view
     */
    public void showKeyboard(View view) {
        InputMethodManager imm = (InputMethodManager) this
                .getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.showSoftInputFromInputMethod(view.getWindowToken(),
                InputMethodManager.HIDE_NOT_ALWAYS);
    }

    /**
	 * show process loading Dialog
	 *
	 * @param tip    remind string
	 * @param listener    dismisslistener
	 */
    //tintColor: true 表示 false 表示

    public void processPreview(final String tip, final PopupWindow.OnDismissListener listener) {
        processPreview(tip, listener, false);
    }

    public void processPreview(final String tip, final PopupWindow.OnDismissListener listener, final boolean isLoginActivity) {
        processDismiss();
        Bundle bundle = new Bundle();
        bundle.putInt(DialogLoadingFragment.GRAVITY, Gravity.CENTER);
        bundle.putInt(DialogLoadingFragment.LAYOUT, R.layout.process_loading);
        //bundle.putInt(BaseDialogFragment.LAYOUT_HEIGHT, ViewGroup.LayoutParams.WRAP_CONTENT);
        //bundle.putInt(BaseDialogFragment.LAYOUT_WIDTH, ViewGroup.LayoutParams.WRAP_CONTENT);
        bundle.putInt(DialogLoadingFragment.LAYOUT_HEIGHT, ViewGroup.LayoutParams.MATCH_PARENT);
        bundle.putInt(DialogLoadingFragment.LAYOUT_WIDTH, ViewGroup.LayoutParams.MATCH_PARENT);
        //bundle.putInt(BaseDialogFragment.WINDOW_ANIM, R.style.AnimFade);
        bundle.putInt(DialogLoadingFragment.WINDOW_ANIM, -1);
        if(isLoginActivity) {
            bundle.putBoolean(DialogLoadingFragment.IS_LOGIN, true);
        }else{
            bundle.putBoolean(DialogLoadingFragment.IS_LOGIN, false);
        }
        bundle.putBoolean(DialogLoadingFragment.DISMISSABLE, false);
        processBar = DialogLoadingFragment.newInstance(bundle, new Runnable() {
            @Override
            public void run() {
                try {
                    if (getWindow() != null && getWindow().isActive() && !FBaseActivity.this.isFinishing()) {
                        if (tip == null) {
                            /*(processBar.getDialog()
                                    .findViewById(R.id.process_text)).setVisibility(View.GONE);*/
                            ((TextView) (processBar.getDialog()
                                    .findViewById(R.id.process_text))).setText("");
                        } else {
                            ((TextView) (processBar.getDialog()
                                    .findViewById(R.id.process_text))).setText(tip);
                        }
                        //processBar.getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
                        //processBar.getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.BLACK));
                        ImageView bigGear = (ImageView) processBar.getDialog().findViewById(R.id.iv_gear_big);
                        ImageView smallGear = (ImageView) processBar.getDialog().findViewById(R.id.iv_gear_small);
                        RelativeLayout layout = (RelativeLayout) processBar.getDialog().findViewById(R.id.loading_layout_need_bg);
                        //RelativeLayout layout_whole = (RelativeLayout) processBar.getDialog().findViewById(R.id.layout_outside_whole_loading);
                        if (isLoginActivity) {//登陆界面, 需要background
                            layout.setBackgroundColor(Color.parseColor("#00000000"));
                        } else {//非登陆界面，无需background
                            layout.setBackgroundResource(R.drawable.loading_bg_shape);
                        }
                        final Animation anim = AnimationUtils.loadAnimation(FBaseActivity.this, R.anim.myanim);
                        LinearInterpolator lir = new LinearInterpolator();
                        anim.setInterpolator(lir);
                        final Animation anim2 = AnimationUtils.loadAnimation(FBaseActivity.this, R.anim.myanim_revert);
                        anim2.setInterpolator(lir);
                        bigGear.startAnimation(anim2);
                        smallGear.startAnimation(anim);
                        if (listener != null) {
                            processBar.getDialog().setCancelable(true);
                            processBar.getDialog().setOnDismissListener(new DialogInterface.OnDismissListener() {
                                @Override
                                public void onDismiss(DialogInterface dialog) {
                                    listener.onDismiss();
                                    Toast.makeText(getApplicationContext(), "任务已经取消", Toast.LENGTH_SHORT).show();
                                }
                            });
                        } else {
                            processBar.getDialog().setCanceledOnTouchOutside(false);
                        }
                    }
                } catch (Exception e) {
                }
            }
        });
        new Handler(Looper.getMainLooper()).post(new Runnable() {
            @Override
            public void run() {
                if (processBar != null) {
                    try {
                        processBar.show(getSupportFragmentManager(), "process");
                    }catch (Exception e){
                        DLog.p(e);
                    }
                }
            }
        });
    }

	/**
	 * dismiss loading dialog
	 */
    public synchronized void processDismiss() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (((ViewGroup) getWindow().getDecorView().findViewById(android.R.id.content)).getChildAt(0) != null)
                    ((ViewGroup) getWindow().getDecorView().findViewById(android.R.id.content)).getChildAt(0).post(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                if (processBar != null && processBar.getDialog().isShowing()) {
                                    ImageView bigGear = (ImageView) processBar.getDialog().findViewById(R.id.iv_gear_big);
                                    ImageView smallGear = (ImageView) processBar.getDialog().findViewById(R.id.iv_gear_small);
                                    bigGear.clearAnimation();
                                    bigGear.clearFocus();
                                    smallGear.clearAnimation();
                                    smallGear.clearFocus();
                                    processBar.dismiss();
                                }
                            } catch (Exception e) {
                            }
                        }
                    });
            }
        });
    }


    @Override
    public void startActivity(Intent intent) {
        hideKeyboard(findViewById(android.R.id.content));
        super.startActivity(intent);
    }

    @Override
    public void startActivity(Intent intent, @Nullable Bundle options){
        hideKeyboard(findViewById(android.R.id.content));
        super.startActivity(intent, options);
    }

    @Override
    public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
        hideKeyboard(findViewById(android.R.id.content));
        super.startActivityForResult(intent, requestCode, options);
    }

    /**
     * ***************************** 【Activity LifeCycle For Debug】 ******************************************
     */

    @Override
    protected void onStart() {
        DLog.d(TAG, this.getClass().getSimpleName() + " onStart() invoked!!");
        super.onStart();
    }

    @Override
    protected void onRestart() {
        DLog.d(TAG, this.getClass().getSimpleName()
                + " onRestart() invoked!!");
        super.onRestart();
    }

    @Override
    protected void onResume() {
        DLog.d(TAG, this.getClass().getSimpleName()
                + " onResume() invoked!!");
        super.onResume();
        DLog.i("intent", getIntent() == null ? "null" : getIntent().getExtras() == null ? "null" : getIntent().getExtras().toString());
        if(getIntent() != null && 0x3f != getIntent().getIntExtra(PRE_RESULT, 0x3f)) {
            int res = getIntent().getIntExtra(PRE_RESULT, Activity.RESULT_CANCELED);
            setResult(res);
        }
        if(!FApplication.DEBUG)
        MobclickAgent.onResume(this);
        FApplication.activityResumed();
    }

    @Override
    protected void onPause() {
        processDismiss();
        DLog.d(TAG, this.getClass().getSimpleName() + " onPause() invoked!!");
        super.onPause();
        if(!FApplication.DEBUG)
        MobclickAgent.onPause(this);
        FApplication.activityPaused();
    }

    @Override
    protected void onStop() {
        DLog.d(TAG, this.getClass().getSimpleName() + " onStop() invoked!!");
        super.onStop();
    }


    @Override
    protected void onDestroy() {
        activities.remove(this);
        //when calling finish, this activity must be removed from activities list at this time
        if(processBar != null) {
            processDismiss();
            processBar = null;
        }

        DLog.d(TAG, this.getClass().getSimpleName() + " onDestroy() invoked!!");

        super.onDestroy();
        for(Activity a : activities) {
            DLog.i("activities", a.getClass().getName());
        }

        BugFix.destoryCallback(this,
                ((ViewGroup) getWindow().getDecorView().findViewById(
                        android.R.id.content)).getChildAt(0)
                );

        RefWatcher refWatcher = FApplication.getRefWatcher();
        refWatcher.watch(this);
    }

	/**
	 * recreate all activities
	 */
    public void recreateAll() {
        for(final Activity a: activities) {
            a.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    a.recreate();
                }
            });
        }
    }


	/**
	 * finish with transasion
	 */
    @Override
    public void finish() {
        super.finish();
        if(!getIntent().getBooleanExtra(FConstants.MAIN_FINISH, false)) {
            //closing transition animations
            overridePendingTransition(R.anim.activity_open_scale, R.anim.activity_close_translate);
        }
    }


	/**
	 * finishall activities in line
	 */
    public static void finishAll(){
        synchronized (activities) {
            for (final Activity a : activities) {
                a.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        activities.remove(a);
                        try {
                            a.finish();
                        } catch (Exception e) {
                        }
                    }
                });
            }
        }
    }

    @Override
    public void recreate() {
        super.recreate();
        overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
    }

	/**
	 * finish without transasion
	 */
    public void defaultFinish() {
        processDismiss();
        super.finish();
    }


	/**
	 * request permission
	 *
	 * @param permission
	 * @param callback
	 */
    public void requestPermission(String permission, Runnable callback) {
        // Here, thisActivity is the current activity
        try {
            if (ContextCompat.checkSelfPermission(ContextManager.context(), permission)
                    != PackageManager.PERMISSION_GRANTED) {

                // Should we show an explanation?
                if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                        permission)) {

                    // Show an expanation to the user *asynchronously* -- don't block
                    // this thread waiting for the user's response! After the user
                    // sees the explanation, try again to request the permission.
                    DLog.w("login:", "setting needed!");
                    new Handler(Looper.getMainLooper()).post(callback);
                } else {
                    // No explanation needed, we can request the permission.
                    ActivityCompat.requestPermissions(this,
                            new String[]{permission}, REQUEST_PERMISSION);
                    permissionCallbacks.put(permission, callback);
                    // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
                    // app-defined int constant. The callback method gets the
                    // result of the request.
                }
            } else {
                new Handler(Looper.getMainLooper()).post(callback);
            }
        }catch (Exception e){
            callback.run();
            //...
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           String permissions[], int[] grantResults) {
        switch (requestCode) {
            case REQUEST_PERMISSION: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                    // permission was granted, yay! Do the
                    // contacts-related task you need to do.
                    new Thread(permissionCallbacks.get(permissions[0])).run();
                } else {

                    // permission denied, boo! Disable the
                    // functionality that depends on this permission.
                    new Thread(permissionCallbacks.get(permissions[0])).run();
                }
            }

            // other 'case' lines to check for other
            // permissions this app might request
        }
        permissionCallbacks.remove(permissions[0]);
    }

    public static synchronized List<Activity> getActivites(){
        return activities;
    }
}
